package com.ghovos.usermangerpgdemo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ghovos.usermangerpgdemo.common.constant.RedisConst;
import com.ghovos.usermangerpgdemo.entity.PermissionEntity;
import com.ghovos.usermangerpgdemo.entity.RoleEntity;
import com.ghovos.usermangerpgdemo.entity.RolePermissionEntity;
import com.ghovos.usermangerpgdemo.mapper.PermissionMapper;
import com.ghovos.usermangerpgdemo.mapper.RoleMapper;
import com.ghovos.usermangerpgdemo.mapper.RolePermissionMapper;
import com.ghovos.usermangerpgdemo.service.PermissionService;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author liuli
 */
@Service
@AllArgsConstructor
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, PermissionEntity> implements PermissionService {

    private final StringRedisTemplate stringRedisTemplate;
    private final RolePermissionMapper rolePermissionMapper;
    private final PermissionMapper permissionMapper;
    private final RoleMapper roleMapper;

    @Override
    public List<PermissionEntity> getAllPermissionExt() {
        List<PermissionEntity> permissionEntities = permissionMapper.selectList(null);
        // 1. 遍历 permissionEntity
        permissionEntities.forEach(permissionEntity -> {
            PermissionEntity extendList = this.getExtendList(permissionEntity.getId());
            permissionEntity.setRoleLists(extendList.getRoleLists());
        });

        return permissionEntities;
    }

    @Override
    public PermissionEntity getPermissionExtById(Long id) {
        PermissionEntity permissionEntity = permissionMapper.selectById(id);
        // 1. 通过中间表查询 关联的 roleIds
        PermissionEntity extendList = this.getExtendList(id);
        permissionEntity.setRoleLists(extendList.getRoleLists());
        return permissionEntity;
    }

    @Override
    public boolean deleteByIdWithRole(Long id) {
        LambdaQueryWrapper<RolePermissionEntity> rolePerListWrapper
                = Wrappers.<RolePermissionEntity>lambdaQuery()
                .eq(RolePermissionEntity::getPermissionId, id);
        // 查询 permission 具体信息
        PermissionEntity permissionEntity = permissionMapper.selectById(id);
        // 找出有关这个id的 role List
        List<RolePermissionEntity> rolePermissionEntities = rolePermissionMapper.selectList(rolePerListWrapper);


        // 遍历rolePermission中间表
        rolePermissionEntities.forEach(rolePermissionEntity -> {
            stringRedisTemplate.opsForSet().remove(
                    RedisConst.ROLE + rolePermissionEntity.getRoleId(),
                    permissionEntity.getUrl()
            );
        });
        rolePermissionMapper.delete(rolePerListWrapper);

        return this.removeById(id);

    }

    @Override
    public PermissionEntity saveOrUpdateWithRedis(PermissionEntity permissionEntity) {
        if (permissionEntity.getId() != null && permissionEntity.getUrl() != null) {
            PermissionEntity permissionById = this.getById(permissionEntity.getId());
            List<RolePermissionEntity> rolePermissionEntities = rolePermissionMapper.selectList(Wrappers.<RolePermissionEntity>lambdaQuery()
                    .eq(RolePermissionEntity::getPermissionId, permissionEntity.getId())
            );
            // 遍历更新redis
            rolePermissionEntities.forEach(rolePermissionEntity -> {
                stringRedisTemplate.opsForSet().remove(
                        RedisConst.ROLE + rolePermissionEntity.getRoleId(),
                        permissionById.getUrl() // 旧的url
                );
                stringRedisTemplate.opsForSet().add(
                        RedisConst.ROLE + rolePermissionEntity.getRoleId(),
                        permissionEntity.getUrl() // 新的url
                );
            });
        }
        // 最后再更新
        this.saveOrUpdate(permissionEntity);
        return permissionEntity;
    }

    @Override
    public void initRedisUrlRole() {

        // 0. 删除全部keys
        Set<String> keys = stringRedisTemplate.keys(RedisConst.ROLE+ "*");
        stringRedisTemplate.delete(Objects.requireNonNull(keys));

        List<PermissionEntity> permissionEntities = permissionMapper.selectList(null);
        // 1. 遍历找到的permission list
        permissionEntities.forEach(permissionEntity -> {
            String url = permissionEntity.getUrl();
            // 2. 通过中间表找到 哪些 角色拥有该权限
            List<RolePermissionEntity> rolePermissionEntities = rolePermissionMapper.selectList(
                    Wrappers.<RolePermissionEntity>lambdaQuery()
                            .eq(RolePermissionEntity::getPermissionId, permissionEntity.getId())
            );
            // 3. 遍历找到的角色 列表
            rolePermissionEntities.forEach(rolePermissionEntity -> {
                // 4. 查询这些角色的名称
                // 5. 存入redis中
                if (permissionEntity.getUrl() != null && !permissionEntity.getUrl().isEmpty()) {
                    stringRedisTemplate.opsForSet().add("role:" + rolePermissionEntity.getRoleId(), url);
                }
            });
        });
    }


    /**
     * 公用方法 , 连表查询 permission 拥有的 role list
     *
     * @return 拥有 list 的 permission 实体
     */
    private PermissionEntity getExtendList(Long permissionId) {
        PermissionEntity permissionEntity = new PermissionEntity();
        // 1. 通过中间表查询 关联的 roleIds
        List<Long> roleIds = rolePermissionMapper.selectList(
                Wrappers.<RolePermissionEntity>lambdaQuery()
                        .eq(RolePermissionEntity::getPermissionId, permissionId)
        ).stream().map(RolePermissionEntity::getRoleId).collect(Collectors.toList());

        // 2. 通过ids 查询 role的详情
        if (!roleIds.isEmpty()) {
            List<RoleEntity> roleEntities = roleMapper.selectBatchIds(roleIds);
            permissionEntity.setRoleLists(roleEntities);
        }
        return permissionEntity;
    }


}
